/* 
 * Cashbox is the legal property of its developers, whose names are listed in the copyright file included
 * with this source distribution.
 * 
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
 * General Public License as published by the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
 * Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this program; if not,
 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#import "CBLabelsPreferenceViewController.h"
#import "CBLabel.h"
#import "ColorListColors.h"
#import <Cashbox/CBDataControllerProtocol.h>

#define DRAG_TYPE		@"LabelsDragType"

static void *CBArrangedObjectsChangeContext = @"CBArrangedObjectsChangeContext";

@interface CBLabelsPreferenceViewController (Private)
- (void)setSelectedLabel:(CBLabel *)label;
@end

@implementation CBLabelsPreferenceViewController

+ (void)registerDefaults {
}

+ (NSString *)nibName {
	return @"LabelsPreferences";
}

- (NSString *)label {
	return @"Labels";
}

- (NSImage *)image {
	return [NSImage imageNamed:@"labels_pref"];
}

- (void)dealloc {
	[labels removeObserver:self forKeyPath:@"arrangedObjects"];
	
	[selectedLabel release];
	[panel release];
	[names release];
	[colors release];
	[super dealloc];
}

- (void)awakeFromNib {
	[labels addObserver:self forKeyPath:@"arrangedObjects" options:0 context:CBArrangedObjectsChangeContext];
	
	[labels setManagedObjectContext:[[cashbox dataController] managedObjectContext]];
	[labels setEntityName:[CBLabel entityName]];
	[labels setSortDescriptors:[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:@"index" ascending:YES] autorelease]]];
	[labels fetchWithRequest:nil merge:NO error:NULL];
	
	[labelsTable registerForDraggedTypes:[NSArray arrayWithObject:DRAG_TYPE]];
	
	NSPopUpButtonCell *cell = [[[labelsTable tableColumns] objectAtIndex:1] dataCell];
	NSMenu *menu = [cell menu];

	names = [COLOR_LIST_TITLE_ARRAY retain];
	colors = [COLOR_LIST_COLOR_ARRAY retain];
	
	int index = 0;
	NSString *name;
	NSColor *color;
	NSEnumerator *nameEnumerator = [names objectEnumerator];
	NSEnumerator *colorEnumerator = [colors objectEnumerator];
	while ((name = [nameEnumerator nextObject]) && (color = [colorEnumerator nextObject])) {
		FSColoredMenuItem *newItem = [[[FSColoredMenuItem alloc] init] autorelease];
		[newItem setTitle:name];
		[newItem setColor:color];
		[menu insertItem:newItem atIndex:index];
		index++;
	}
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
	if (context == CBArrangedObjectsChangeContext) {
		// display the table
		[labelsTable reloadData];
		// make sure the selection is up to date as well
		[self tableViewSelectionIsChanging:nil];
	}
}

#pragma mark getter/setter methods
// ----------------------------------------------------------------------------------------------------
// getter/setter methods
// ----------------------------------------------------------------------------------------------------

- (void)setSelectedLabel:(CBLabel *)label {
	if (selectedLabel != label) {
		[selectedLabel release];
		selectedLabel = [label retain];
	}
}

#pragma mark interface actions
// ----------------------------------------------------------------------------------------------------
// interface actions
// ----------------------------------------------------------------------------------------------------

- (IBAction)colorChange:(id)sender {
	CBLabel *label = selectedLabel;
	if (label) { [label setColor:[sender color]]; }
	[labelsTable reloadData];
}

- (IBAction)showColorPanel:(id)sender {
	if (!panel) {
		panel = [[NSColorPanel alloc] init];
		[panel setContinuous:YES];
		[panel setTarget:self];
		[panel setAction:@selector(colorChange:)];
	}
	[panel setColor:[selectedLabel color]];
	[panel makeKeyAndOrderFront:nil];
}

- (void)addLabel:(id)sender {
	CBLabel *label = [[[CBLabel alloc] initWithIndex:[[labels arrangedObjects] count]  andInsertIntoManagedObjectContext:[[cashbox dataController] managedObjectContext]] autorelease];
	[label setName:FSLocalizedString(@"Untitled Label", nil)];
	[label setColor:[colors firstObject]];
	[[[cashbox dataController] managedObjectContext] processPendingChanges];
	[labelsTable selectRow:[[labels arrangedObjects] indexOfObject:label] byExtendingSelection:NO];
	[self setSelectedLabel:label];
	[labelsTable editColumn:0 row:[labelsTable selectedRow] withEvent:nil select:YES];
}

- (void)removeLabel:(id)sender {
	CBLabel *label = selectedLabel;
	if (label) {
		NSBeginAlertSheet([NSString stringWithFormat:FSLocalizedString(@"Delete the label %@?", nil), [label name]],
						  FSLocalizedString(@"Delete", nil),
						  FSLocalizedString(@"Cancel", nil),
						  nil,
						  [[self view] window],
						  self,
						  @selector(removeLabelDidEnd:returnCode:contextInfo:),
						  nil,
						  label,
						  [NSString stringWithFormat:FSLocalizedString(@"Any transactions using this label will no longer have any label.  Are you sure you want to delete the label %@?", nil), [label name]]);
	}
}

- (void)removeLabelDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void  *)contextInfo {
	CBLabel *label = contextInfo;
	if (returnCode == NSAlertDefaultReturn) {
		// delete the label
		[[[cashbox dataController] managedObjectContext] deleteObject:label];
	}
}

#pragma mark table view delegate and data source
// ----------------------------------------------------------------------------------------------------
// table view delegate and data source
// ----------------------------------------------------------------------------------------------------

- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(int)row {
	if ([cell isKindOfClass:[FSOvalTextFieldCell class]]) {
		NSColor *color = [[[labels arrangedObjects] objectAtIndex:row] valueForKey:@"color"];
		[cell setOvalColor:color];
	} else if ([cell isKindOfClass:[NSPopUpButtonCell class]]) {
		NSColor *color = [[[labels arrangedObjects] objectAtIndex:row] valueForKey:@"color"];
		if ([colors containsObject:color]) { [other setColor:nil]; }
		else { [other setColor:color]; }
	}
}

- (void)tableViewSelectionIsChanging:(NSNotification *)notification {
	if ([labelsTable selectedRow] != -1) { [self setSelectedLabel:[[labels arrangedObjects] objectAtIndex:[labelsTable selectedRow]]]; }
	else { [self setSelectedLabel:nil]; }
	
	// ensure the "other color" is right before the popup appears
	if ([colors containsObject:[selectedLabel color]]) { [other setColor:nil]; }
	else { [other setColor:[selectedLabel color]]; }
	
	if (panel) { [panel close]; }
}


- (int)numberOfRowsInTableView:(NSTableView *)tableView {
	return [[labels arrangedObjects] count];
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row {
	if ([[tableColumn identifier] isEqualToString:@"name"]) {
		return [[[labels arrangedObjects] objectAtIndex:row] valueForKey:@"name"];
	} else if ([[tableColumn identifier] isEqualToString:@"color"]) {
		int index;
		NSColor *color;
		NSMenuItem *menuItem;
		NSEnumerator *menuItemEnumerator;
		
		color = [[[labels arrangedObjects] objectAtIndex:row] valueForKey:@"color"];
		if (color) {
			index = 0;
			menuItemEnumerator = [[[[tableColumn dataCell] menu] itemArray] objectEnumerator];
			while (menuItem = [menuItemEnumerator nextObject]) {
				if ([menuItem isKindOfClass:[FSColoredMenuItem class]] &&
					[[(FSColoredMenuItem *)menuItem color] isEqualTo:color]) {
					return [NSNumber numberWithInt:index];
				}
				index++;
			}		
		}
		
		index = [[[tableColumn dataCell] menu] numberOfItems]-1;
		return [NSNumber numberWithInt:index];	
	}
	return nil;
}

- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(int)row {
	if ([[tableColumn identifier] isEqualToString:@"name"]) {
		[[[labels arrangedObjects] objectAtIndex:row] setValue:object forKey:@"name"];
	} else if ([[tableColumn identifier] isEqualToString:@"color"]) {
		int index = [object intValue];
		NSMenuItem *menuItem = [[[tableColumn dataCell] menu] itemAtIndex:index];
		if ([menuItem isKindOfClass:[FSColoredMenuItem class]]) {
			NSColor *color = [(FSColoredMenuItem *)menuItem color];
			[[[labels arrangedObjects] objectAtIndex:row] setValue:color forKey:@"color"];
		}
	}
}

#pragma mark table view drag and drop
// ----------------------------------------------------------------------------------------------------
// table view drag and drop
// ----------------------------------------------------------------------------------------------------

- (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard*)pboard {
	if ([rowIndexes count]) {
		[pboard declareTypes:[NSArray arrayWithObject:DRAG_TYPE] owner:self];
		[pboard setPropertyList:[NSNumber numberWithInt:[rowIndexes firstIndex]] forType:DRAG_TYPE];
		return TRUE;
	} else {
		return FALSE;
	}
}

- (NSDragOperation)tableView:(NSTableView *)aTableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)operation {
	if (operation == NSTableViewDropAbove) {
		return NSDragOperationGeneric;
	} else {
		return NSDragOperationNone;
	}
}

- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id <NSDraggingInfo>)info row:(int)dragToRow dropOperation:(NSTableViewDropOperation)operation {
	int dragFromRow;
	id draggedObject;
	NSPasteboard *pboard;
	NSNumber *dragFromRowNumber;
	NSArrayController *controller = labels;
	
	pboard = [info draggingPasteboard];
	dragFromRowNumber = [pboard propertyListForType:DRAG_TYPE];
	dragFromRow = [dragFromRowNumber intValue];
	
	if (dragToRow > dragFromRow) { dragToRow--; }
	draggedObject = [[controller arrangedObjects] objectAtIndex:dragFromRow];
	
	int index = 0;
	id current;
	NSEnumerator *enumerator = [[controller arrangedObjects] objectEnumerator];
	while (current = [enumerator nextObject]) {
		if (index == dragToRow) { index++; } // keep space at the row we're dragging to
		if (current != draggedObject) { // treat the one that's moving differently
			[current setIndex:index];
			index++;
		} else {
			[draggedObject setIndex:dragToRow];
		}
	}
	
	[controller rearrangeObjects];
	[controller setSelectionIndex:dragToRow];
	return YES;
}


@end
